package co.edu.unal.bioingenium.kbmed.knowledge.visualization.vo;

import com.thoughtworks.xstream.annotations.XStreamOmitField;
import java.util.*;

/**
 *
 * @author alejandro
 */
public class SubHierarchy {

    private String name;
    private SubHierarchyNode root;
    @XStreamOmitField
    private Map<String, SubHierarchyNode> nodeMap;

    /**
     *
     */
    private SubHierarchy() {
        nodeMap = new HashMap<String, SubHierarchyNode>();
    }

    /**
     *
     * @param name
     * @param root
     */
    public SubHierarchy(String name) {
        this();
        this.name = name;

    }

    /**
     *
     * @return
     */
    public String getName() {
        return name;
    }

    /**
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     *
     * @return
     */
    public SubHierarchyNode getRoot() {
        return root;
    }

    /**
     *
     * @param nodeId
     * @return
     */
    public SubHierarchyNode getNode(String nodeId) {
        return nodeMap.get(nodeId);
    }

    public boolean containsNode(String nodeId) {
        if ((getNode(nodeId)) != null) {
            return true;
        }
        return false;
    }

    /**
     *
     * @param parentdNodeId
     * @param childNode
     */
    public void addChildrenNode(String parentdNodeId, SubHierarchyNode childNode) {
        SubHierarchyNode parentNode;
        if ((parentNode = getNode(parentdNodeId)) != null) {
            if (!parentNode.hasChildren(childNode)) {
                parentNode.addChildren(childNode);
                childNode.addParent(parentdNodeId);
                nodeMap.put(childNode.getId(), childNode);
            }
        }
    }

    public List<String> getMultipleHineritanceNodes() {
        List<String> multipleHineritanceNodes = new ArrayList<String>();
        getMultipleHineritanceNodes(root, multipleHineritanceNodes);
        return multipleHineritanceNodes;
    }

    public void getMultipleHineritanceNodes(SubHierarchyNode currentNode, List<String> multipleHineritanceNodes) {
        Set<SubHierarchyNode> childrens = currentNode.getChildren();
        for (SubHierarchyNode childNode : childrens) {
            getMultipleHineritanceNodes(childNode, multipleHineritanceNodes);
        }
        if (currentNode.getParent().size() > 1) {
            if (!multipleHineritanceNodes.contains(currentNode.getId())) {
                multipleHineritanceNodes.add(currentNode.getId());
            }
        }
    }

    public void fixMultipleHineritance() {
        List<String> multipleHineritanceNodeList = getMultipleHineritanceNodes();
        SubHierarchyNode node, clonNode;
        Set<String> parents;
        String parentId;
        SubHierarchyNode parentNode;
        int count;
        for (String nodeId : multipleHineritanceNodeList) {
            node = nodeMap.get(nodeId);
            parents = node.getParent();
            count = 0;
            for (Iterator<String> it = parents.iterator(); it.hasNext();) {
                parentId = it.next();
                if (count > 0) {
                    clonNode = (SubHierarchyNode) node.clone();
                    fixCloneNodeIds(clonNode, parentId);
                    parentNode = nodeMap.get(parentId);
                    parentNode.removeChild(node);
                    addChildrenNode(parentId, clonNode);
                    it.remove();
                }
                count++;
            }
        }
    }

    public void fixCloneNodeIds(SubHierarchyNode currentNode, String parentId) {
        currentNode.setId(currentNode.getId() + "-" + parentId);
        Set<SubHierarchyNode> childrens = currentNode.getChildren();
        for (SubHierarchyNode childNode : childrens) {
            fixCloneNodeIds(childNode, parentId);
        }
    }

    public SubHierarchyNode getSubHierarchyNodeInstance(String conceptId, String descriptorId, String category, String term) {
        SubHierarchyNode node;
        if ((node = nodeMap.get(conceptId)) != null) {
            return node;
        }
        return new SubHierarchyNode(conceptId, descriptorId, category, term);
    }

    public void setRoot(String conceptId, String descriptorId, String category, String term) {
        root = getSubHierarchyNodeInstance(conceptId, descriptorId, category, term);
        nodeMap.put(root.getId(), root);
    }
}
